/** *************************************************************************
 *  @file       basic_cfg.c
 *  @brief	    基础配置函数
 *  @date		2021/11/26 
 *  @author		junshuai.li
 *  @version	3.3.0
 ****************************************************************************/
#include "basic_cfg.h"

//用于判断是否为第一次version.txt
u8 flag_file_open_num = 0;


//存储节点版本信息数目
u8 total_node_version_num = 0;


void fwrite_file(u8 *const locla_mac,u64 hw_version,u8 *const name)
{
	FILE *fp = NULL;

	u8 buf[100] = {0};
	if(flag_file_open_num == 0)
	{
		fp = fopen("./version.txt", "w");
		flag_file_open_num++;
	}		
	else
		fp = fopen("./version.txt", "a+");
	sprintf(buf, "%s\n", "*************************");
	fwrite(buf, sizeof(char), strlen(buf), fp);

	fwrite(name, sizeof(char), strlen(name), fp);
	sprintf(buf, "%s\n", ": ");
	fwrite(buf, sizeof(char), strlen(buf), fp);
	
	sprintf(buf, "local_mac = %02x:%02x:%02x:%02x:%02x:%02x\n", locla_mac[0],locla_mac[1],locla_mac[2],locla_mac[3],locla_mac[4],locla_mac[5]);
	fwrite(buf, sizeof(char), strlen(buf), fp);
	
	
	sprintf(buf, "version = 0x%llx\n", hw_version);
	fwrite(buf, sizeof(char), strlen(buf), fp);
	fclose(fp);

	return;
}

int startup_l2switch_exe(u8 *network_inetrface)
{
	char tmp_buf[64] = {0};
	sprintf(tmp_buf, "sh %s %s", L2SWITCH_EXE_SHELL_FILENAME,network_inetrface);
	system(tmp_buf);

	printf("*************L2SWITCH_EXE OK********************\n");
}


u32 get_hw_version(u8 *local_mac,u8 *pkt,u8 type)
{
	int ret = 0;
	u32 *read_data = NULL;
    u32 version = 0;
	u32 addr=0;
	u8 name[8] = {0};

	if(type == 1)
	{
		addr = htonl(HCP_VER_REG);
		strcpy(name,"HCP");
	}
	else if(type == 2)
	{
		addr = htonl(TSS_VER_REG);
		strcpy(name,"TSS");
	}
	else if(type == 3)
	{
		addr = htonl(OS_VER_CFG);
		strcpy(name,"OS");
	}
	
	//读请求
	tsmp_get_req(local_mac,1,addr,pkt);
	read_data = tsmp_get_res(local_mac,1,addr);//读响应
	if(read_data == NULL)
	{
		write_debug_msg("get_hw_version tsmp_get_res error");
		printf("get_hw_version tsmp_get_res error");
		return 0;
	}
	
	version = ntohl(*read_data);
	
	fwrite_file(local_mac,version,name);

	//清空pkt
	bzero(pkt,2048);

	return version;
	
}



 void tsmp_fwd_init(u8 *local_mac,u8 *pkt)
 {
	int i = 0;
	u16 data_num = 0;
	
	u32 addr = 0;//配置的地址	
	u32 *data = NULL;

	//清空pkt
	bzero(pkt,2048);
	
	//data内容直接放到pkt中，省去再次赋值
	data = (u32 *)(pkt + sizeof(tsmp_header) + sizeof(tsmp_set_req_or_get_res_pkt_data));//配置的数据
	 
	 //TSMP转发表初始化，TSMP转发表总共4096条表项，每条表项2个寄存器，因此每次配置128条表项，总共配置32次
	 for(i = 0; i< 32 ;i++)
	 { 
		 addr = MID_TABLE + 2*128*i;
		 data_num = 2*128; 
		 tsmp_set_req(local_mac,data_num,htonl(addr),pkt);//写请求
	 }


	  //配置TSMP转发表使能为1
	  //data[0] = htonl(0x4);
	  //tsmp_set_req(local_mac,1,htonl(HCP_CFG_REG),pkt);//写请求

	  bzero(pkt,2048);

	 return ;
 }


void riprt_n(char *str)
 {
	 int len, i;
 
	 if (str == NULL)
		 return;
	 len = strlen(str);
	 if (len == 0) 
		 return;
 
	 for (i = 0; i < len; i++)
	 {
		 if (str[i] == '\r' || str[i] == '\n')
			 str[i] = '\t';
	 }
 }

//解析每条转发表项
int parse_tsmp_fwd_entry(cJSON *entry_json, u32 *data,u16 *dmid)
{

	u16 tvalue16 = 0;
	u64 tvalue64 = 0;
	u32 tvalue32 = 0;
	char* endptr=NULL;

	cJSON *tmp_json=NULL;

	//printf("parse_mac_fwd_entry start! \n");

	if(data == NULL)
	{
		printf("parse_mac_fwd_entry,data = NULL! \n");
		return -1;
	}
	
	//获取TSMP转发表信息
	tmp_json =cJSON_GetObjectItem(entry_json, "dmid");

	if(NULL == tmp_json)
	{
		printf("can not find  dmid object!\n");
		return -1;
	}
	else
	{
		sscanf(tmp_json->valuestring, "%hx", &tvalue16);
		*dmid = tvalue16;
		printf("dmid 0x%x \n",*dmid);
	}


	tmp_json =cJSON_GetObjectItem(entry_json, "outport");

	if(NULL == tmp_json)
	{
		printf("can not find  outport object!\n");
		return -1;
	}
	else
	{
		tvalue64 = strtoull(tmp_json->valuestring,&endptr,16);//十六进制转换

		tvalue32 = (u32)(tvalue64>>32);
		tvalue32 = 0x80000000 + tvalue32;
		data[0] = htonl(tvalue32);
		printf("outport data[0] 0x%x \n",tvalue32);

		tvalue32 = (u32)(tvalue64&0xffffffff);
		data[1] = htonl(tvalue32);
		printf("outport data[1] 0x%x \n",tvalue32);
	}
		
	return 0;

}


int basic_cfg_and_parse_tsmp_fwd(cJSON *entry_json, u8 *local_mac,u8 *pkt)
{
	int array_num = 0;
	int i = 0;
	int ret = 0;
		
	cJSON *tmp_json=NULL;
	
	u16 data_num = 0;
	u16 mid = 0;
	u8 cmp_mac[6] = {0};
	
	u32 addr = 0;//配置的地址	
	u32 *data = NULL;

	//验证是否已正确获取local_mac，如果是则可以继续运行
	if(memcmp(local_mac,cmp_mac,6) == 0)
	{
		printf("basic_cfg_and_parse_tsmp_fwd,error: local_mac is 0\n");
		return -1;
	}


	if(pkt == NULL)
	{
		printf("basic_cfg_and_parse_mac_fwd,pkt = NULL! \n");
		return -1;
	}

	//data内容直接放到pkt中，省去再次赋值
	data = (u32 *)(pkt + sizeof(tsmp_header) + sizeof(tsmp_set_req_or_get_res_pkt_data));//配置的数据

	//有多个节点情况
	if(entry_json->type == cJSON_Array)
	{
		array_num = cJSON_GetArraySize(entry_json);
		printf("array_num = %d \n", array_num);

		if(array_num == 0)
		{
			printf("basic_cfg_and_parse_tsmp_fwd, array_num = 0! \n");
			return -1;
		}

		for (i = 0; i < array_num; i++)
		{
			tmp_json = cJSON_GetArrayItem(entry_json,i);

			if (!tmp_json) 
			{
				printf("basic_cfg_and_parse_tsmp_fwd entry_json error, Error before: [%s]\n",cJSON_GetErrorPtr());
				return -1;
			}

			//获取单条tsmp转发表信息
			ret = parse_tsmp_fwd_entry(tmp_json,data,&mid);
			if(ret == -1)
			{
				printf("parse_tsmp_fwd_entry error!\n");
				return -1;
			}

			addr = MID_TABLE + 2*mid;
		    data_num = 2; 
	
		    tsmp_set_req(local_mac,data_num,htonl(addr),pkt);//写请求

		    //配置验证
		    ret = cfg_varify(local_mac,data_num,htonl(addr),pkt);

		    //配置验证失败，程序退出
			if(ret == -1)
			{
				printf("varify parse_tsmp_fwd_entry error!addr=%x,dmid=%x \n",addr,mid);
				return -1;
			}
		}
	}
	else if(entry_json->type == cJSON_Object)
	{
		//获取单个节点的基础信息
		ret = parse_tsmp_fwd_entry(entry_json,data,&mid);
		if(ret == -1)
		{
			printf("parse_tsmp_fwd_entry error!\n");
			return -1;
		}

		addr = MID_TABLE + 2*mid;
	    data_num = 2; 

	    tsmp_set_req(local_mac,data_num,htonl(addr),pkt);//写请求

	    //配置验证
	    ret = cfg_varify(local_mac,data_num,htonl(addr),pkt);

	    //配置验证失败，程序退出
		if(ret == -1)
		{
			printf("varify parse_tsmp_fwd_entry error!addr=%x,dmid=%x \n",addr,mid);
			return -1;
		}
	}	

	return 0;
}

 


int basic_cfg_and_parse_node_object(cJSON *node_json, u8 *pkt,u16 tsnlight_mid,node_mid_table* table, node_ver_table* version_table)
{
	u16 tvalue16 = 0;
	u16 hcp_mid = 0;

	int ret = 0;
	int array_num = 0;
	int i = 0;
		
	cJSON *hcp_mid_json=NULL;
	cJSON *tsmp_fwd_tbl_json=NULL;
	cJSON *entry_json=NULL;
	cJSON *tmp_json=NULL;

	u8 local_mac[6] = {0};
	u32 tvalue = 0;
	//定义一个变量存储配置内容
	u32* tmp_data = NULL;

	tmp_data = (u32 *)(pkt + sizeof(tsmp_header) + sizeof(tsmp_set_req_or_get_res_pkt_data));//配置的数据

	
	// 获取节点hcp_mid信息
	hcp_mid_json =cJSON_GetObjectItem(node_json, "hcp_mid");

	if(NULL == hcp_mid_json)
	{
		printf("can not find  hcp_mid object!\n");
		return -1;
	}
	else
	{
		sscanf(hcp_mid_json->valuestring, "%hx", &tvalue16);
		hcp_mid = tvalue16;
		
		printf("hcp_mid 0x%hx \n", hcp_mid);

		table->node_mid[table->num] = hcp_mid;

		get_hcp_mac_from_mid(local_mac,hcp_mid);

		//（1）发送mid分配帧，分配节点hcp和TSNLightd的mid，未校验
		tsmp_cfg_hcp_tsnlight_mid(local_mac,hcp_mid,tsnlight_mid,pkt);
		
	}

	// 获取节点tsmp_forward_table信息
	tsmp_fwd_tbl_json =cJSON_GetObjectItem(node_json, "tsmp_forward_table");

	if(NULL == tsmp_fwd_tbl_json)
	{
		printf("can not find  tsmp_forward_table object!\n");
	}
	else
	{
	 	//（2）TSMP转发表初始化及TSMP转发表使能为1
		tsmp_fwd_init(local_mac,pkt);

		entry_json =cJSON_GetObjectItem(tsmp_fwd_tbl_json, "entry");
		if(NULL == entry_json)
		{
			printf("can not find  entry_json object!\n");
			return -1;
		}

		 /* （3）找到tsmp_forward_table每条表项，并进行配置tsmp转发表 */
		ret = basic_cfg_and_parse_tsmp_fwd(entry_json,local_mac,pkt);
		if(ret == -1)
		{
			printf("basic_cfg_and_parse_tsmp_fwd error!\n");
			return -1;
		}
		
	}

		//（5）校验HCP和tsnlight的MID
	tmp_data[0] = (tsnlight_mid<<12)|hcp_mid;
	//printf("tmp_data[0] = %x \n",tmp_data[0]);
	tmp_data[0] = htonl(tmp_data[0]);

	
	ret = cfg_varify(local_mac,1,htonl(HCP_MID_REG),pkt);
	if(ret == -1)
	{
		printf("varify HCP and tsnlight MID error!\n");
		return -1;
	}


	/*（6）获取版本号*/
	tvalue = 0;
	version_table[table->num].node_mid = htonl(hcp_mid);
	tvalue = get_hw_version(local_mac,pkt,1);//HCP版本号
	version_table[table->num].hcp_ver = htonl(tvalue);
	tvalue = get_hw_version(local_mac,pkt,2);//TSS版本号
	version_table[table->num].tss_ver = htonl(tvalue);
	tvalue = get_hw_version(local_mac,pkt,3);//OS版本号
	version_table[table->num].os_ver = htonl(tvalue);
	
	printf("end basic_cfg_and_parse_node_object!\n");
	
	return 0;
}


int basic_cfg_and_parse_node(char* buf,u8 *pkt,u16 tsnlight_mid,node_mid_table* table, node_ver_table* version_table)
{
	int ret = 0;
	int array_num = 0;
	int i = 0;
	u16 tvalue16 = 0;
	u8 cur_node_num = 0;
	
	cJSON *root_json=NULL;
	cJSON *network_init_cfg_json=NULL;

	cJSON *node_json=NULL;
	cJSON *tmp_json=NULL;
	
	riprt_n(buf);
	root_json=cJSON_Parse(buf);

	if (!root_json) 
	{
		printf("parse root_json error, Error before: [%s]\n",cJSON_GetErrorPtr());
		return -1;
	}
	
	network_init_cfg_json = cJSON_GetObjectItem(root_json, "network_init_cfg");
	if (!network_init_cfg_json) 
	{
		printf("parse network_init_cfg error, Error before: [%s]\n",cJSON_GetErrorPtr());
		cJSON_Delete(root_json);
		return -1;
	}

	node_json = cJSON_GetObjectItem(network_init_cfg_json, "node");
	if (!node_json) 
	{
		printf("parse node_json error, Error before: [%s]\n",cJSON_GetErrorPtr());
		cJSON_Delete(root_json);
		return -1;
	}

	//有多个节点情况
	if(node_json->type == cJSON_Array)
	{
		array_num = cJSON_GetArraySize(node_json);
		printf("array_num = %d \n", array_num);

		if(array_num == 0)
		{
			printf("parse_basic_info, node = NULL! \n");
			cJSON_Delete(root_json);
			return -1;
		}

		for (i = 0; i < array_num; i++)
		{
			tmp_json = cJSON_GetArrayItem(node_json,i);

			if (!tmp_json) 
			{
				printf("parse basic_node_entry_json error, Error before: [%s]\n",cJSON_GetErrorPtr());
				cJSON_Delete(root_json);
				return -1;
			}

			//获取单个节点的基础信息
			ret = basic_cfg_and_parse_node_object(tmp_json,pkt,tsnlight_mid,table,version_table);
			if(ret == -1)
			{
				printf("basic_cfg_and_parse_node_object error!\n");
				cJSON_Delete(root_json);
				return -1;
			}

			cur_node_num++;
			table->num = cur_node_num;
			
		}
	}
	else if(node_json->type == cJSON_Object)
	{
		//获取单个节点的基础信息
		ret = basic_cfg_and_parse_node_object(node_json,pkt,tsnlight_mid,table,version_table);
		if(ret == -1)
		{
			printf("basic_cfg_and_parse_node_object error!\n");
			cJSON_Delete(root_json);
			return -1;
		}
		
		cur_node_num++;
		table->num = cur_node_num;
	}

	printf("table->num=%d \n",table->num);

	cJSON_Delete(root_json);
	
    return ret;
	
}


int basic_cfg_and_parse_file(u8 *init_cfg_file_name,u8 *pkt,u16 tsnlight_mid,node_mid_table* table, node_ver_table* version_table)
{
	int ret = 0;
	
	FILE *fp;
	char *buf;
	fp = fopen(init_cfg_file_name,"r");

	if(fp == NULL)
	{
		printf("fopen %s error\n",init_cfg_file_name);
		return -1;
	}
			
    // 确定文件大小, 并将读取指针移回文件开始
    fseek(fp, 0, SEEK_END);
    long pos = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    if (pos <= 0) 
	{
        printf("%s Invalid!\n",init_cfg_file_name);
		fclose(fp);
		return -1;
    }
	
    // 根据文件大小申请内存空间, 注意这边要多申请1个字节用于存放'\0'
    buf = (char*)malloc(pos + 1);
    if (buf == NULL) {
        printf("No enough memory.");
		fclose(fp);
		return -1;
    }
	bzero(buf, pos + 1);
	
    // 读取文件内容至buff
    int nread = fread(buf, pos, 1, fp);
    if (!nread) {
        printf("Failed to read the config file.");
		free(buf);
		fclose(fp);
		return -1;
    }

    //解析json，获取各个节点初始配置信息
	ret = basic_cfg_and_parse_node(buf,pkt,tsnlight_mid,table,version_table);

	if(buf != NULL)
	{
		free(buf);
	}
	
    // 关闭文件
	fclose(fp);

	return ret;
}




//基础配置的入口函数
int basic_cfg(u8 *network_inetrface,int tsn_type, u32 sw_ver,u16 tsnlight_mid,node_mid_table* table, node_ver_table* version_table)
{
		
	int ret = 0;

	//申请空间，用于构造配置报文
	u8 *pkt = NULL;
	u8 *init_cfg_file_name = NULL;

	char temp_net_interface[16]={0};
	
	pkt = (u8 *)malloc(MAX_PKT_LEN);
	if(NULL == pkt)
	{
		printf("basic_cfg,malloc buf fail\n");
		return -1;
	}
	
	bzero(pkt,MAX_PKT_LEN);
	
	init_cfg_file_name = INIT_CFG_FILE;//初始配置文本

	//解析初始配置文本,解析一个表项，配置一个表项
	ret = basic_cfg_and_parse_file(init_cfg_file_name,pkt,tsnlight_mid,table, &version_table[0]);
	if(ret == -1)
	{
		printf("parse_init_cfg_file fail\n");
		return -1;
	}

	//释放基础配置申请的空间
	free(pkt);

	if(tsn_type)
   {
		memset(temp_net_interface,0,16);
		strcpy(temp_net_interface,"3");
	 	write_debug_msg("TSN_SIM \n");
		startup_l2switch_exe(temp_net_interface);
   }
   else
	{
		write_debug_msg("TSN_FPGA \n");		
		startup_l2switch_exe(network_inetrface);
	}


	printf("*************enter LOCAL_PLAN_CFG_S********************\n");
	write_debug_msg("*************enter LOCAL_PLAN_CFG_S********************\n");

	return ret;
		
}
		
